<script setup lang="ts">
import Chat from "./components/chat/index.vue";
import Player from "./components/player/index.vue";
import UserList from "./components/user-list.vue";
import Setting from "./components/setting/index.vue";
import FullscreenLoading from "./components/fullscreen-loading.vue";

import { onBeforeUnmount, onMounted, provide, reactive, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useUserStore } from "@/store";
import { useMessage } from "naive-ui";
import { useToast } from "@/components/toast-provider/api.ts";

import { VideoState, WS } from "@/pages/room/ws/ws.ts";
import HistoryUserStore from "@/pages/room/HistoryUserStore.ts";
import {
    createMessageListener,
    createRoomInitListener,
    createUserJoinListener,
    createUserLeaveListener,
    createVideoChangeListener,
    createVideoSeekedListener,
    createVideoSpeedListener,
    createVideoStateListener
} from "@/pages/room/ws/listener";
import {
    WS_AUTHENTICATION_FAILURE_CLOSE_STATUS,
    WS_ROOM_CLOSED_CLOSE_STATUS
} from "@/pages/room/constant/close-status-constants.ts";

import { ROOM_CLOSED_ROUTE_NAME } from "@/router/routes/room.route.ts";
import { LOGIN_ROUTE_NAME } from "@/router/routes/login.route.ts";
import { HOME_ROUTE_NAME } from "@/router/routes/home.route.ts";
import { MESSAGE_MAX_LENGTH } from "@/pages/room/constant/validation-constants.ts";

import { ChatMessageType } from "@/pages/room/components/chat/chat-message.ts";

import type { PlayerInst } from "@/pages/room/components/player/player.ts";
import type { ReactiveData } from "@/pages/room/model.ts";

const route = useRoute();
const router = useRouter();
const userStore = useUserStore();
const toast = useToast();
const message = useMessage();

const playerRef = ref<PlayerInst>();
const fullscreen = ref(false);

const data = reactive<ReactiveData>({
    loading: true,
    loadingDescription: "正在连接到房间...",
    room: undefined,
    chats: [],
    chatMessage: ""
});

/**
 * 存储本次进入房间后加入过房间的所有用户信息
 * 避免用户离开房间后用户信息丢失导致聊天列表出问题
 */
const historyUserStore = new HistoryUserStore();

const ws = new WS("/room", {
    ...route.query
});
provide("ws", ws);

function handleSendMessage() {
    if (data.chatMessage.length === 0) {
        return;
    }
    if (data.chatMessage.length > MESSAGE_MAX_LENGTH) {
        message.warning(`消息过长, 仅${MESSAGE_MAX_LENGTH}字以内`);
        return;
    }
    ws?.emit("message", {
        details: {
            message: data.chatMessage
        }
    });
    data.chatMessage = "";
}



onMounted(() => {
    ws
        .addEventListener("error", function (ev) {
            message.error("连接房间失败");
        })
        .addEventListener("close", function (ev) {
            // 正常关闭连接, 取消弹窗处理, 此时可能是正常退出房间
            if (ev.code === 1000) {
                return
            }
            if (ev.code === WS_ROOM_CLOSED_CLOSE_STATUS) {
                return router.push({ name: ROOM_CLOSED_ROUTE_NAME });
            }
            if (ev.code === WS_AUTHENTICATION_FAILURE_CLOSE_STATUS) {
                return router.push({ name: LOGIN_ROUTE_NAME }).then(() => {
                    message.error("登录失效");
                });
            }
            router.push({ name: HOME_ROUTE_NAME }).then(() => {
                message.error("与房间断开连接");
            });
        })
        .on("room.init", createRoomInitListener(data, historyUserStore, playerRef.value!!))
        .on("user.join", createUserJoinListener(data, historyUserStore))
        .on("user.leave", createUserLeaveListener(data, historyUserStore))
        .on("message", createMessageListener(data, historyUserStore, function (type, sender, content) {
            if (fullscreen.value && type === ChatMessageType.OTHER) {
                playerRef.value?.danmu({
                    text: `${sender.nickname}说: ${content}`
                });
            }
        }))
        .on("video.state", createVideoStateListener(data, playerRef.value!!, function (operator, state) {
            switch (state) {
                case VideoState.PLAY: {
                    toast.info(`${historyUserStore.get(operator)?.nickname}开始播放视频`);
                    break;
                }
                case VideoState.PAUSE: {
                    toast.info(`${historyUserStore.get(operator)?.nickname}暂停了视频`);
                    break;
                }
            }
        }))
        .on("video.seeked", createVideoSeekedListener(data, playerRef.value!!, function (operator, time) {
            toast.info(`${historyUserStore.get(operator)?.nickname}调整了视频进度`);
        }))
        .on("video.speed", createVideoSpeedListener(data, playerRef.value!!, function (operator, speed) {
            toast.info(`${historyUserStore.get(operator)?.nickname}更改视频倍速: x${speed.toFixed(2)}`);
        }))
        .on("video.change", createVideoChangeListener(data, function () {
            toast.info(`房主切换了视频`);
        }))
        .connect();
});
onBeforeUnmount(() => {
    ws?.disconnect();
});

function onPlayerPlay() {
    ws.emit("video.state", {
        details: {
            state: VideoState.PLAY
        }
    });
}

function onPlayerPause() {
    ws.emit("video.state", {
        details: {
            state: VideoState.PAUSE
        }
    });
}

function onPlayerSeeked(time: number) {
    ws.emit("video.seeked", {
        details: {
            time: time * 1000
        }
    });
}

function onPlayerRateChange(rate: number) {
    ws.emit("video.speed", {
        details: {
            speed: rate
        }
    });
}

function onPlayerFullscreen(isFullscreen: boolean) {
    fullscreen.value = isFullscreen;
}

</script>

<template>
    <div class="h-full">
        <!-- 全屏加载 -->
        <fullscreen-loading :loading="data.loading" :description="data.loadingDescription"/>
        <!-- 房间界面 -->
        <div class="h-full flex gap-2 flex-col" v-show="!data.loading">
            <!-- 视频播放器 -->
            <player
                ref="playerRef"
                :src="data.room?.video?.url"
                @play="onPlayerPlay"
                @pause="onPlayerPause"
                @seeked="onPlayerSeeked"
                @ratechange="onPlayerRateChange"
                @fullscreen="onPlayerFullscreen"
            />
            <!-- 聊天框 -->
            <chat class="flex-grow" :messages="data.chats"/>
            <!-- 房间内用户列表 -->
            <div class="flex justify-between px-5 gap-5">
                <user-list :current="userStore._user" :users="data.room?.users" class="flex-grow"/>
                <!-- 右侧按钮 -->
                <div v-if="data.room && userStore._user?.id === data.room.creator.id" class="flex-shrink-0 flex items-center justify-center">
                    <setting :room="data.room"/>
                </div>
            </div>
            <!-- 消息输入框 -->
            <div class="p-5 pt-0 flex">
                <n-input-group>
                    <n-input size="large" :show-count="true" :maxlength="MESSAGE_MAX_LENGTH" v-model:value="data.chatMessage" clearable round placeholder="输入聊天内容(Enter发送)" @keydown.enter="handleSendMessage"/>
                    <n-button size="large" round ghost @click="handleSendMessage">发送</n-button>
                </n-input-group>
            </div>
        </div>
    </div>
</template>

<style scoped>

</style>
